<?php

/*@LICENSE@*/

require_once 'Clouseau/Genealogy/Node.php';

/**
 * An abstraction for genealogy trees.
 * @author Thomas Quémard <thomas.quemard@gmail.com>
 **/

abstract class Clouseau_Genealogy extends Clouseau_Genealogy_Node
{
	protected $_aBaseClasses = array();
	protected $_oTree;
	protected $_sName = 'Object';
	protected $_bRemoveSelf = TRUE;
	
	protected function _getAllChildren()
	{
		return array();
	}

	protected function _getParentOf($sName)
	{
		return array();
	}

	public function build($aBaseClasses=NULL)
	{
		return $this->buildFrom(NULL, $aBaseClasses);
	}

	public function buildFrom($aClasses=array(), $aBaseClasses=NULL)
	{
		if (!is_array($aBaseClasses))
		{
			$this->_aBaseClasses = array();
		}
		else
		{
			$this->_aBaseClasses = $aBaseClasses;
		}

		if (is_array($aClasses))
		{
			$aRaw = $aClasses;
		}
		else
		{
			$aRaw = $this->_getAllChildren();
		}
		$aNodes = array();

		foreach ($aRaw as $sClass)
		{
			$oNode = new Clouseau_Genealogy_Node;
			$oNode->setName($sClass);
			$aNodes[$sClass] = $oNode;
		}
		unset($aRaw);

		foreach ($aNodes as $oNode)
		{
			$sParent = $this->_getParentOf($oNode->getName());

			if (empty($sParent))
			{
				$this->append($oNode);
			}
			else
			{
				$aNodes[$sParent]->append($oNode);
			}
		}

		// Remove the base classes unless they are used by another class.
		if (count($this->_aBaseClasses)>0)
		{
			//echo 'HAS_BAS_CLASSES' . "\n";
			$this->_removeBaseClasses($this);
		}
	}
	public function _removeBaseClasses(Clouseau_Genealogy_Node &$oNode)
	{
		$b = TRUE;
		for ($i=0, $iCount=$oNode->count(); $i<$iCount; ++$i)
		{
			$oChild = $oNode[$i];
			if (!is_null($oChild))
			{
				if (in_array($oChild->getName(), $this->_aBaseClasses))
				{
					if ($oChild->count()>0)
					{
						if ($this->_removeBaseClasses($oNode[$i])===TRUE)
						{
							$oNode->offsetUnset($i);
						}
					}
					else
					{
						$oNode->offsetUnset($i);
					}
				}
				else
				{
					$b = FALSE;
				}
			}
		}

		return $b;
	}
	
	public function removeSelf($b=TRUE)
	{
		$this->_bRemoveSelf = (bool)$b;
	}
}


